import http from '@ohos.net.http'
import systemDateTime from '@ohos.systemDateTime'
import { Constant } from '../Constant'
import { sub } from '../utils/Calc'
import { RequestMethod, RequestOptions } from './RequestOptions'

/**
 * Http请求器
 * https://blog.csdn.net/hzw2017/article/details/134910847
 */
export class HttpCore {
  private tag: string = 'HttpUtils'

  /**
   * 默认headers 与 传进来的headers 拼接
   */
  private defaultHeader(header?: Object): Object {
    let customHeader = {}
    if (header) { //传进来的header
      return Object.assign(header, customHeader)
    } else {
      return customHeader
    }
  }

  /**
   * 发送请求
   * @param requestOption
   * @returns Promise
   */
  request<T>(requestOption: RequestOptions, method: RequestMethod): Promise<T> {
    return new Promise<T>((resolve, reject) => {
      this.sendRequest(requestOption, method)
        .then((response) => {
          if (typeof response.result !== 'string') {
            reject(new Error('Invalid data type'))
          } else {
            let bean: T = JSON.parse(response.result)
            if (bean) {
              resolve(bean)
            } else {
              reject(new Error('Invalid data type,JSON to T failed'))
            }
          }
        })
        .catch((error) => {
          reject(error)
        })
    })
  }

  private async sendRequest(requestOption: RequestOptions, method: RequestMethod): Promise<http.HttpResponse> {

    // 每一个httpRequest对应一个HTTP请求任务，不可复用
    let httpRequest = http.createHttp()

    let resolveFunction, rejectFunction
    const resultPromise = new Promise<http.HttpResponse>((resolve, reject) => {
      resolveFunction = resolve
      rejectFunction = reject
    })

    if (!this.isValidUrl(requestOption.url)) {
      return Promise.reject(new Error('url格式不合法.'))
    }

    let questUrl = this.appendQueryParams(Constant.baseUrl + requestOption.url, requestOption.queryParams)
    let headers = this.defaultHeader(requestOption.header)
    console.debug(this.tag, "==================Request====================")
    console.debug(this.tag, "url: " + questUrl.replace(/\//g, "%"))
    console.debug(this.tag, "method: " + method.toString())
    this.printLog('header', JSON.stringify(headers), -1)
    if (method == RequestMethod.POST || method == RequestMethod.PUT) {
      this.printLog('extraData', JSON.stringify(requestOption.extraData), -1)
    }
    let beginTime = await systemDateTime.getCurrentTime(false)
    httpRequest.request(
      questUrl, {
      method: method,
      header: headers,
      extraData: requestOption.extraData, // 当使用POST请求时此字段用于传递内容
      expectDataType: http.HttpDataType.STRING, // 可选，指定返回数据的类型
      readTimeout: 10_000,
      connectTimeout: 10_000
    }).then(async (response) => {
      let endTime = await systemDateTime.getCurrentTime(false)
      console.debug(this.tag, "==================Response====================")
      console.debug(this.tag, "url: " + questUrl.replace(/\//g, "%") + " " + sub(endTime, beginTime) + "ms")
      console.debug(this.tag, "method: " + method.toString())
      this.printLog('header', JSON.stringify(response.header), -1)
      console.debug(this.tag, "responseCode: " + response.responseCode)
      if (http.ResponseCode.MOVED_PERM === response.responseCode
      || http.ResponseCode.MOVED_TEMP === response.responseCode) {//重定向
        // requestOption.url = httpRequest.
        // this.sendRequest(requestOption, method)
        console.debug(this.tag, '300+: ' + JSON.stringify(response))
      } else if (http.ResponseCode.OK !== response.responseCode) {
        console.debug(this.tag, 'error: ' + JSON.stringify(response))
      } else {
        resolveFunction(response)
        this.printLog('body', JSON.stringify(response.result))
      }
    }).catch((err) => {
      rejectFunction(err)
      console.debug(this.tag, 'error: ' + JSON.stringify(err))
    }).finally(() => {
      // 当该请求使用完毕时，调用destroy方法主动销毁。
      httpRequest.destroy()
    })
    return resultPromise
  }

  private appendQueryParams(url: string, queryParams: Record<string, any>): string {
    // todo 使用将参数拼接到url上
    if (queryParams) {
      let params = ''
      for (let queryParamsKey in queryParams) {
        if (params) {
          params = params + '&' + queryParamsKey + '=' + queryParams[queryParamsKey]
        } else {
          params = queryParamsKey + '=' + queryParams[queryParamsKey]
        }
      }
      return url + '?' + params
    }
    return url
  }

  private isValidUrl(url: string): boolean {
    //todo 实现URL格式判断
    return true
  }

  /**
   * 打印完整日志
   * @param log 日志类型
   * @param content 日志内容
   * @param maxPrint -1 日志长度限制，-1：表示不限制
   */
  private printLog(log: string, content?: string, maxPrint: number = 1000) {
    if (content) {
      let length = maxPrint === -1 ? content.length : maxPrint
      let speed = 255
      let start = 0
      let end = speed
      if (length <= speed) {
        console.debug(this.tag, log + ': ' + content)
      } else {
        this.printLogFor(log, content, start, end, speed, length)
      }
    }
  }

  //递归打印
  private printLogFor(log: string, content: string, start: number, end: number, speed: number, length: number) {
    console.debug(this.tag, log + ': ' + content.substring(start, end).replace(/\//g, '%'))
    if (end < length) {
      start = end
      end = start + speed > length ? length : start + speed
      this.printLogFor(log, content, start, end, speed, length)
    }
  }
}

export const httpCore = new HttpCore()


